package gptma.bo.model.task;

import gptma.bo.model.BaseEntity;
import gptma.bo.model.employee.Employee;
import gptma.bo.model.project.Project;
import gptma.bo.model.request.ClientRequest;
import java.util.ArrayList;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.AttributeOverride;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
@Table(name = "tache")
@AttributeOverride(name = "id", column = @Column(name = "tacheId"))
public class Task extends BaseEntity {

	private static final long serialVersionUID = -7399923019921561211L;

	@NotNull
	@Column(name = "code")
	private String code;

	@NotNull
	@Column(name = "libelle")
	private String label;

	@Column(name = "tacheGenerique")
	private Boolean administrative;

	@Column(name = "commentaire")
	private String comment;

	@Digits(integer = 2, fraction = 2)
	@Column(name = "chargeVendue")
	private Float soldCharge;

	@Column(name = "statutEnCours")
	private String currentState;

	@OneToOne
	@JoinColumn(name = "demandeClientId")
	private ClientRequest clientRequest;

	// TODO: LazyInitializationException is managed here (was lazy before)
	// find a better way to do that: either OSIV or FetchingStrategy object
	@OneToOne
	@JoinColumn(name = "projetDirectementRattacheId")
	private Project directlyAttachedProject;

	@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
	@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "task", orphanRemoval = true)
	private Set<Assignment> assignments;

	public Project getAttachedProject() {
		Project ret = null;

		if (clientRequest != null) {
			ret = clientRequest.getProject();
		} else {
			ret = directlyAttachedProject;
		}

		return ret;
	}

	public void addAssignment(Assignment assignment) {
		if (this.assignments == null) {
			this.assignments = new HashSet<Assignment>();
		}

		this.assignments.add(assignment);
		assignment.setTask(this);
	}

	public List<Employee> getAssignedEmployees() {
		Set<Employee> ret = new HashSet<Employee>();
		for (Assignment assignment : assignments) {
			ret.add(assignment.getEmployee());
		}

		return new ArrayList<Employee>(ret);
	}

	public int getAssignedEmployeesNb() {
		return getAssignedEmployees().size();
	}

	/**
	 * @return the code
	 */
	public String getCode() {
		return code;
	}

	/**
	 * @param code
	 *            the code to set
	 */
	public void setCode(String code) {
		this.code = code;
	}

	/**
	 * @return the label
	 */
	public String getLabel() {
		return label;
	}

	/**
	 * @param label
	 *            the label to set
	 */
	public void setLabel(String label) {
		this.label = label;
	}

	/**
	 * @return the administrative
	 */
	public Boolean getAdministrative() {
		return administrative;
	}

	/**
	 * @param administrative
	 *            the administrative to set
	 */
	public void setAdministrative(Boolean administrative) {
		this.administrative = administrative;
	}

	/**
	 * @return the comment
	 */
	public String getComment() {
		return comment;
	}

	/**
	 * @param comment
	 *            the comment to set
	 */
	public void setComment(String comment) {
		this.comment = comment;
	}

	/**
	 * @return the soldCharge
	 */
	public Float getSoldCharge() {
		return soldCharge;
	}

	/**
	 * @param soldCharge
	 *            the soldCharge to set
	 */
	public void setSoldCharge(Float soldCharge) {
		this.soldCharge = soldCharge;
	}

	/**
	 * @return the clientRequest
	 */
	public ClientRequest getClientRequest() {
		return clientRequest;
	}

	/**
	 * @param clientRequest
	 *            the clientRequest to set
	 */
	public void setClientRequest(ClientRequest clientRequest) {
		this.clientRequest = clientRequest;
	}

	/**
	 * @return the directlyAttachedProject
	 */
	public Project getDirectlyAttachedProject() {
		return directlyAttachedProject;
	}

	/**
	 * @param directlyAttachedProject
	 *            the directlyAttachedProject to set
	 */
	public void setDirectlyAttachedProject(Project directlyAttachedProject) {
		this.directlyAttachedProject = directlyAttachedProject;
	}

	/**
	 * @return the assignments
	 */
	public Set<Assignment> getAssignments() {
		return assignments;
	}

	/**
	 * @param assignments
	 *            the assignments to set
	 */
	public void setAssignments(Set<Assignment> assignments) {
		this.assignments = assignments;
	}

	/**
	 * @return the currentState
	 */
	public String getCurrentState() {
		return currentState;
	}

	/**
	 * @param currentState
	 *            the currentState to set
	 */
	public void setCurrentState(String currentState) {
		this.currentState = currentState;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Task other = (Task) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}

}
